package system

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"likeadmin/admin/schemas/req"
	"likeadmin/admin/schemas/resp"
	"likeadmin/constant"
	"likeadmin/core/request"
	"likeadmin/core/response"
	"likeadmin/dao"
	"likeadmin/model"
	"likeadmin/util"
	"math/rand"
	"strconv"
	"time"
)

type IUserService interface {
	List(c *gin.Context, page request.PageReq, req req.UserListReq) (res response.PageResp, e error)
	Detail(c *gin.Context, id int32) (res resp.UserResp, e error)
	EditField(c *gin.Context, req req.UserEditReq) (e error)
	AdjustMoney(c *gin.Context, req req.AdjustMoneyReq) (e error)
	GenerateSN(randSuffixLength int) int32
}

// NewUserService 初始化
func NewUserService(dao *dao.Query) IUserService {
	return &userService{dao: dao}
}

// userService 系统管理员服务实现类
type userService struct {
	dao *dao.Query
}

func (userSrv userService) List(c *gin.Context, page request.PageReq, listReq req.UserListReq) (res response.PageResp, e error) {
	// 分页信息
	limit := page.PageSize
	offset := page.PageSize * (page.PageNo - 1)
	// 总数
	var count int64
	u := userSrv.dao.User
	q := u.WithContext(c)

	// 账号 昵称 真实姓名 电话 模糊匹配 条件
	if listReq.Keyword != "" {
		q = q.Where(q.Where(u.Account.Like("%" + listReq.Keyword + "%")).
			Or(u.RealName.Like("%" + listReq.Keyword + "%")).
			Or(u.Nickname.Like("%" + listReq.Keyword + "%")).
			Or(u.Mobile.Like("%" + listReq.Keyword + "%")))

	}
	// 时间范围查询
	if listReq.CreateTimeStart != "" && listReq.CreateTimeEnd != "" {
		startTime, err := util.DateToTimestamp(listReq.CreateTimeStart)
		if e = response.CheckErr(err, "DateToTimestamp err"); e != nil {
			return
		}

		endTime, err := util.DateToTimestamp(listReq.CreateTimeEnd)
		if e = response.CheckErr(err, "DateToTimestamp err"); e != nil {
			return
		}

		q = q.Where(u.CreateTime.Gt(int32(startTime)), u.CreateTime.Lt(int32(endTime)))
	}

	// 渠道查询
	if listReq.Channel > 0 {
		q = q.Where(u.Channel.Eq(listReq.Channel))
	}

	q = q.Where(u.IsDisable.Eq(0))

	count, err := q.Count()
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}

	users, err := q.Limit(limit).Offset(offset).Find()
	if e = response.CheckErr(err, "List Find err"); e != nil {
		return
	}
	for _, user := range users {
		user.Avatar = util.UrlUtil.ToAbsoluteUrl(user.Avatar)
	}

	var lists []resp.UserResp
	response.Copy(&lists, users)

	return response.PageResp{
		PageNo:   page.PageNo,
		PageSize: page.PageSize,
		Count:    count,
		Lists:    lists,
	}, nil
}

// Detail 用户信息详情
func (userSrv userService) Detail(c *gin.Context, id int32) (res resp.UserResp, e error) {
	u := userSrv.dao.User
	user, err := u.WithContext(c).Where(u.ID.Eq(id)).First()
	if err != nil {
		return resp.UserResp{}, err
	}
	if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
		return
	}
	if e = response.CheckErr(err, "Detail First err"); e != nil {
		return
	}
	response.Copy(&res, user)
	res.Avatar = util.UrlUtil.ToAbsoluteUrl(res.Avatar)
	return
}

// Detail 用户信息详情
func (userSrv userService) EditField(c *gin.Context, req req.UserEditReq) (e error) {
	u := userSrv.dao.User
	_, err := u.WithContext(c).Where(u.ID.Eq(req.Id)).Updates(map[string]interface{}{req.Field: req.Value, "update_time": time.Now().Unix()})
	if e = response.CheckErrDBNotRecord(err, "数据不存在!"); e != nil {
		return
	}
	if e = response.CheckErr(err, "EditField Updates err"); e != nil {
		return
	}

	return
}

// AdjustMoney 增加扣除用户余额
func (userSrv userService) AdjustMoney(c *gin.Context, req req.AdjustMoneyReq) (err error) {
	d := userSrv.dao
	tx := d.Begin()
	u := d.User
	defer func() {
		if recover() != nil || err != nil {
			_ = tx.Rollback()
		}
	}()

	user, e := u.WithContext(c).Where(u.ID.Eq(req.Id)).First()
	if err = response.CheckErrDBNotRecord(e, "数据不存在!"); err != nil {
		return
	}
	if err = response.CheckErr(e, "Detail First err"); err != nil {
		return
	}

	if req.Action == constant.INC {
		// 给余额和充值总数加上金额
		_, e = tx.User.WithContext(c).Where(u.ID.Eq(req.Id)).UpdateSimple(u.UserMoney.Add(req.Num))
		if err = response.CheckErr(e, "增加余额失败"); err != nil {
			return
		}

		// 写入余额变化日志
		e = tx.UserAccountLog.Create(&model.UserAccountLog{
			Sn:           user.Sn,
			UserID:       user.ID,
			ChangeObject: constant.GetChangeObject(constant.UmIncAdmin),
			ChangeType:   constant.UmIncAdmin,
			Action:       constant.INC,
			ChangeAmount: req.Num,
			LeftAmount:   user.UserMoney + req.Num,
			Remark:       req.Remark,
			CreateTime:   int32(time.Now().Unix()),
		})
		if err = response.CheckErr(e, "UserAccountLog Create err"); err != nil {
			return
		}

	} else if req.Action == constant.DEC {
		// 检查余额是否大于等当前值
		if user.UserMoney < req.Num {
			err = response.CheckErr(errors.New("余额不足"), "扣除余额失败")
			return
		}
		// 给余额和充值总数减去金额
		_, e = tx.User.WithContext(c).Where(u.ID.Eq(req.Id)).UpdateSimple(u.UserMoney.Sub(req.Num))
		if err = response.CheckErr(e, "扣除余额失败"); err != nil {
			return
		}

		UserMoney := decimal.NewFromFloat(user.UserMoney).Round(2)
		Num := decimal.NewFromFloat(req.Num).Round(2)
		m, _ := UserMoney.Sub(Num).Float64()

		// 写入余额变化日志
		e = tx.UserAccountLog.Create(&model.UserAccountLog{
			Sn:           user.Sn,
			UserID:       user.ID,
			ChangeObject: constant.GetChangeObject(constant.UmIncAdmin),
			ChangeType:   constant.UmDecAdmin,
			Action:       constant.DEC,
			ChangeAmount: req.Num,
			LeftAmount:   m,
			Remark:       req.Remark,
			CreateTime:   int32(time.Now().Unix()),
		})
		if err = response.CheckErr(e, "UserAccountLog Create err"); err != nil {
			return
		}
	}

	return tx.Commit()
}

// 生成随机单号
func (userSrv userService) GenerateSN(randSuffixLength int) int32 {
	suffix := ""
	for i := 0; i < randSuffixLength; i++ {
		suffix += strconv.Itoa(rand.Intn(10))
	}

	sn := time.Now().Format("20060102150405") + suffix
	Sn, _ := strconv.ParseInt(sn, 10, 32)

	ua := userSrv.dao.UserAccountLog
	_, err := ua.Where(ua.Sn.Eq(Sn)).Select(ua.Sn).Take()
	if err == gorm.ErrRecordNotFound {
		return int32(Sn)
	}
	return userSrv.GenerateSN(randSuffixLength)

}
